package deployr.domain;

import static java.text.MessageFormat.*;
import static java.util.Collections.*;

import java.io.*;
import java.util.*;

import deployr.core.*;

public class Project implements Serializable, IProject {

	private static final long serialVersionUID = 8592078904385672792L;

	private final String artifactId;

	private String checksum = "";

	private final List<IEvent> events = new LinkedList<IEvent>();

	private final String groupId;

	private Date lastUpdated = new Date();

	private String path = "";

	private String projectKey = "";

	private String status = "";

	private final List<IUpdate> updates;

	private final String version;

	private SaveOn saveOnPlace;

	public Project(final String groupId, final String artifactId, final String version) {
		this(groupId, artifactId, version, new LinkedList<IUpdate>());
	}

	public Project(Metadata metadata) {
		this(metadata, new LinkedList<IUpdate>());
	}

	public Project(Metadata metadata, List<IUpdate> updates) {
		this(metadata.get("groupId"), metadata.get("artifactId"), metadata.get("version"), updates);
	}

	public Project(String groupId, String artifactId, String version, List<IUpdate> updates) {
		this.groupId = groupId;
		this.artifactId = artifactId;
		this.version = version;
		this.projectKey = makeProjectKey(groupId, artifactId, version);
		this.path = makePath(groupId, artifactId, version);
		this.updates = updates;
	}

	public Event addEvent(final String name, final Date now) {
		status = name;
		final Event event = new Event(name, now);
		events.add(0, event);
		return event;
	}

	public String getArtifactId() {
		return artifactId;
	}

	public String getChecksum() {
		return checksum;
	}

	public IUpdate createUpdate() {
		final Update update = new Update(new Artifact(groupId, artifactId, version), updates.size() + 1);
		updates.add(0, update);
		save();
		return update;
	}

	@Override
	public boolean equals(final Object obj) {
		if (obj == null) return false;
		if (!Project.class.isAssignableFrom(obj.getClass())) return false;
		return ((Project) obj).projectKey.equals(projectKey);
	}

	public Iterable<IEvent> findEvents() {
		return unmodifiableList(events);
	}

	public String getGroupId() {
		return groupId;
	}

	public Date getLastUpdated() {
		return lastUpdated;
	}

	public String getPath() {
		return path;
	}

	public boolean pathEqualsTo(final String path) {
		if (getPath().equals(path)) return true;
		return false;
	}

	public boolean pathStartsWith(final String path) {
		return getPath().startsWith(path);
	}

	public String getProjectKey() {
		return projectKey;
	}

	@Override
	public void removeUpdatesAndEraseChecksum() {
		removeUpdates();
		eraseChecksum();
		save();
	}

	private void removeUpdates() {
		updates.clear();
	}

	public Status getStatus() {
		return new Status(status);
	}

	@Override
	public String toString() {
		return projectKey;
	}

	public void updateChecksum(final String checksum) {
		this.checksum = checksum;
		save();
	}

	public Iterable<IUpdate> findUpdates() {
		return unmodifiableList(updates);
	}

	public String getVersion() {
		return version;
	}

	protected void eraseChecksum() {
		checksum = "";
	}

	protected void save() {
		lastUpdated = new Date();
		if (null != saveOnPlace) saveOnPlace.save(this);
	}

	private String makePath(final String groupId, final String artifactId, final String version) {
		return format("/{0}/{1}/{2}", groupId.replaceAll("\\.", "/"), artifactId, version);
	}

	private String makeProjectKey(final String groupId, final String artifactId, final String version) {
		return new Artifact(groupId, artifactId, version).checksum();
	}

	@Override
	public Artifact getArtifact() {
		return new Artifact(getGroupId(), getArtifactId(), getVersion());
	}

	protected void setChecksum(String checksum) {
		this.checksum = checksum;
	}

	public void setLastUpdateDate(Date lastUpdateDate) {
		this.lastUpdated = lastUpdateDate;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public boolean isNot(IProject anotherProject) {
		return !is(anotherProject);
	}

	public boolean is(IProject project) {
		return equals(project);
	}

	public void saveOn(SaveOn saveOnPlace) {
		this.saveOnPlace = saveOnPlace;
	}
	
	@Override
	public int updatesCount() {
		return updates.size();
	}
}